#include <iostream>
#include <string>
#include <vector>
#include "libnet.h"

using namespace std;

// Liste de tous les clients connectés au serveur
struct ClientOnServer
{
  SocketServer server_client;
  string pseudo;
  pthread_t cli_thread;
};

// variables globales
SocketServer server;
vector<ClientOnServer*> server_clients;

typedef vector<ClientOnServer*>::iterator client_iterator;

void broadcastmsg(string msg)
{
  client_iterator it;
  for(it = server_clients.begin(); it != server_clients.end(); ++it)
    (*it)->server_client.writeLine(msg.c_str());
}

void broadcastmsg(string msg, string pseudo)
{
  client_iterator it;
  for(it = server_clients.begin(); it != server_clients.end(); ++it)
    {
      if((*it)->pseudo != pseudo)
	(*it)->server_client.writeLine(("["+pseudo+"] "+msg).c_str());
    }
}

// Threads qui récupèrent les messages recus par les clients (sur le serveur)
void *readInput(void *arg)
{
  ClientOnServer *client = (ClientOnServer*)(arg);
  string line = "";
  while(line != "exit")
    {
      line = client->server_client.readLine();
      cout << "[" << client->pseudo << "] " << line << endl;
      if(line == "exit")
	{
	  broadcastmsg(client->pseudo+" s'est déconnecté");
	  cout << client->pseudo+" s'est déconnecté" << endl;
	  client_iterator it;
	  bool erased = false;
	  for(it = server_clients.begin(); it != server_clients.end() && !erased; ++it)
	    if((*it)->pseudo == client->pseudo)
	      {
		delete client;
		it = server_clients.erase(it);
		erased = true;
	      }
	}
      else
	broadcastmsg(line, client->pseudo);
    }
}

// Thread qui attend des connections de clients et les ajoutes à la liste
void *getConnections(void *arg)
{
  while(1)
    {
      ClientOnServer *client = new ClientOnServer;
      client->server_client = server.accept_connection();
      // A mettre en thread pour optimiser
      client_iterator it;
      bool pseudo_ok = false, exist;
      string pseudo = "";
      client->server_client.writeLine("Entrez un pseudo svp");
      while(!pseudo_ok)
	{
	  pseudo = client->server_client.readLine();
	  if(pseudo != "" && pseudo != "SERVER")
	    {
	      exist = false;
	      for(it = server_clients.begin(); it != server_clients.end() && !exist; ++it)
		if((*it)->pseudo == pseudo)
		  exist = true;
	    }
	  else
	    exist = true;
	  if(exist == true)
	    client->server_client.writeLine("Pseudo incorrect");
	  else
	    {
	      client->server_client.writeLine("Vous etes maintenant connecté");
	      broadcastmsg(pseudo+" s'est connecté");
	      cout << pseudo+" s'est connecté" << endl;
	      client->pseudo = pseudo;
	      pseudo_ok = true;
	    }
	}
      pthread_create(&client->cli_thread,
		     NULL,
		     readInput,
		     (void*)(client));
      server_clients.push_back(client);
    }
}

void clean()
{
  client_iterator it;
  for(it = server_clients.begin(); it != server_clients.end(); ++it)
    {
      delete (*it);
      it = server_clients.erase(it);
    }
}

int main(int argc, char **argv)
{
  if(argc < 2)
    {
      cerr << "Error : A port is needed to start the server" << endl;
      return 0;
    }
  
  pthread_t getco;
  server = SocketServer(atoi(argv[1]));

  pthread_create(&getco, NULL, getConnections, NULL);

  string line = "";
  while(line != "exit")
    {
      getline(cin, line);
      broadcastmsg(line, "SERVER");
    }

  clean();
  
  return 0;
}
